package oop6

import "fmt"

/*
中序遍历一棵树结构（对应的main()在 struct7.go）
 	TIPS：
		1. 使用包的方式将main方法和结构体、方法以及函数等分开；
		2. 一个目录下只能有一个包，如果想一个目录下的文件不同包名，可以在目录下再建一个子目录，然后在这个子目录中使用其他包名；
		3. 结构体的方法或函数只能在放在同一包内
*/

/*
通过构造函数形式得到一个节点

*/
func Constructor(val int) *TreeNode {

	return &TreeNode{Value: val}
}

/*
通过函数方式设置节点值
*/
func SetValue(node *TreeNode, val int) {

	node.Value = val
}

/*
通过方法方式设置节点值
*/
func (node *TreeNode) InitValue(val int) {

	node.Value = val
}

/*
通过方法形式打印节点值
*/
func (node *TreeNode) Print() {

	fmt.Print(node.Value, " ")
}

/*
中序遍历节点
 	TIPS：在二叉树中，中序遍历首先遍历左子树，然后访问根结点，最后遍历右子树
*/
func (node *TreeNode) Reverse() {

	// 退出条件是节点为nil
	if node == nil {
		return
	}

	// 先左子树
	node.LeftNode.Reverse()
	// 在中间
	node.Print()
	// 后右子树
	node.RightNode.Reverse()
}

/*
后序遍历
	TIPS：在二叉树中，后续遍历首先遍历左子树，然后遍历右子树，最后访问根结点
*/
func (node *TreeNode) PostOrder() {

	if node == nil {
		return
	}

	// 在左子树
	node.LeftNode.PostOrder()
	// 再右子树
	node.RightNode.PostOrder()
	// 后中间
	node.Print()
}

/*
前序遍历
	TIPS：在二叉树中，前序遍历首先访问根结点，然后遍历左子树，最后遍历右子树

	函数作为参数值的方式。这样就能实现lambda 表达式的效果了，而不像中序和后续遍历只能打印节点值作用。使用这种方式就能
	根据想要的结果来实现函数内的代码
*/
func (node *TreeNode) PreOrderFunc(f func(*TreeNode)) {

	if node == nil {
		return
	}

	// 根节点
	f(node)
	// 左子树
	node.LeftNode.PreOrderFunc(f)
	// 右子树
	node.RightNode.PreOrderFunc(f)
}

/*
使用通道方式前序遍历
*/
func (node *TreeNode) PreOrderFuncChannel() chan int {

	ints := make(chan int)
	go func() {
		defer close(ints)
		node.PreOrderFunc(func(node *TreeNode) {
			ints <- node.Value
		})
	}()

	return ints
}
